{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 问题：用python实现单例模式\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "面试官想从这道题中考察面试人什么？\n",
    "单例模式在很多地方都存在争议，但是，它作为一种最简单和使用广泛的设计模式，在面试中碰到这个问题也是很正常的。\n",
    "\n",
    "答案\n",
    "单例模式的实现有好多方式，在拓展部分介绍了几种常见的，答案具体参见拓展部分。\n",
    "\n",
    "拓展\n",
    "下面这段是维基百科对单例模式的介绍:\n",
    "\n",
    "单例模式，也叫单子模式，是一种常用的软件设计模式。在应用这个模式时，单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象，这样有利于我们协调系统整体的行为。比如在某个服务器程序中，该服务器的配置信息存放在一个文件中，这些配置数据由一个单例对象统一读取，然后服务进程中的其他对象再通过这个单例对象获取这些配置信息。这种方式简化了在复杂环境下的配置管理。\n",
    "\n",
    "我们在什么情况下会用到单例模式呢？\n",
    "\n",
    "系统只需要一个实例对象（如 windows 的资源管理器、唯一序列号生成器、Python 中的 None 对象、某些UI窗口）；\n",
    "客户调用类的单个实例只允许使用一个公共访问点，除了该公共访问点，不能通过其他途径访问该实例。\n",
    "使用单例模式的好处：\n",
    "\n",
    "资源共享，避免由于资源操作时导致的性能或损耗等。如日志文件，应用配置；\n",
    "控制资源，方便资源之间的互相通信。如线程池等。\n",
    "Tips: Python中实现单例模式，我们可以理解为，无论在什么情况下实例化一个单例对象，它所引用的对象都是同一个。那么，与之相反的就是多例模式，即返回多个（有限个）实例对象，可以随机也可以按序。\n",
    "\n",
    "方法一：通过装饰器实现\n",
    "\n",
    "def singleton(class_):\n",
    "    instances = {}\n",
    "    def getinstance(*args, **kwargs):\n",
    "        if class_ not in instances:\n",
    "            instances[class_] = class_(*args, **kwargs)\n",
    "        return instances[class_]\n",
    "    return getinstance\n",
    "\n",
    "@singleton\n",
    "class MyClass():\n",
    "    pass\n",
    "优点：\n",
    "\n",
    "装饰器的添加方式通常比多重继承更直观。\n",
    "缺点：\n",
    "\n",
    "因为 MyClass 是一个函数对象，所以我们无法再进行类方法调用。那么，装饰器修饰的单例类不能再有子类，否则在加载子类时会出错。另外，我们也不能使用type去创建单例，就像下面这个例子一样，a 和 b 引用的是同一个对象，但是 c 不是。\n",
    ">>> a = MyClass()\n",
    ">>> b = MyClass()\n",
    ">>> a == b\n",
    "True\n",
    ">>> c = type(a)()\n",
    ">>> a == c\n",
    "False\n",
    ">>> b == c\n",
    "False\n",
    "方法二：通过__new__方法实现\n",
    "\n",
    "class Singleton2():\n",
    "    def __new__(cls, *args, **kw):\n",
    "        if not hasattr(cls, '_instance'):\n",
    "            orig = super(Singleton2, cls)\n",
    "            cls._instance = orig.__new__(cls)\n",
    "        return cls._instance\n",
    "\n",
    "class BaseClass():\n",
    "    pass\n",
    "\n",
    "class MyClass2(Singleton2，BaseClass):\n",
    "    pass\n",
    "优点：\n",
    "\n",
    "单例类是一个真实的类。\n",
    "缺点：\n",
    "\n",
    "多重继承的问题，如果 MyClass2 不光只继承了 Singleton2，还继承另外一个类 BaseClass，那么__new__可能会被第二个基类改写，这样就有可能影响到无法实现单例。\n",
    "方法三：通过元类实现\n",
    "\n",
    "class Singleton3(type):\n",
    "    _instances = {}\n",
    "    def __call__(cls, *args, **kwargs):\n",
    "        if cls not in cls._instances:\n",
    "            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)\n",
    "        return cls._instances[cls]\n",
    "\n",
    "# MyClass3的基类\n",
    "class BaseClass():\n",
    "    pass\n",
    "\n",
    "class MyClass3(BaseClass, metaclass=Singleton3):\n",
    "    pass\n",
    "优点：\n",
    "\n",
    "方法三其实就是对前两种方法的缺点修正。第一个方法的缺点是没办法把它当类处理，方法三可以，方法二在多重继承的时候可能有隐患，而方法三把这个隐患也根除了。\n",
    "小结\n",
    "这一章中，我们反复强调 Python 语言的动态特性，这使得它能够支持像鸭子类型，白鹅类型和猴子补丁的特性。设计模式之单例模式的使用场景和好处。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}